package cn.ydw.www.plugin.utils;

import android.Manifest;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.DocumentsProvider;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;
import android.webkit.MimeTypeMap;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.List;
import java.util.Locale;


/**
 * @author 杨德望
 * Create on 2018/3/7
 * 描述: 文件工具类
 */
@SuppressWarnings({"unused", "UnusedReturnValue", "WeakerAccess", "DeprecatedIsStillUsed"})
public class FileUtils {
    /**
     * 获取总缓存
     *
     * @param context 上下文
     * @return 格式化后的数据长度
     * @deprecated 不建议使用这个方法
     */
    @Deprecated
    public static String getTotalCacheSize(Context context) {
        long cacheSize = getFolderSize(context.getCacheDir());
//        Logger.e("打印", "缓存getCacheDir数据" + cacheSize);
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            cacheSize += getFolderSize(context.getExternalCacheDir());
//            Logger.e("打印", "缓存getExternalCacheDir数据" + cacheSize);
        }
//        File file = new File(BitmapUtils.IMAGE_FILE_PATH);
//        if (file.isDirectory()){
//            cacheSize += getFolderSize(file);
//            Logger.e("打印", "缓存IMAGE_FILE_PATH数据" + cacheSize);
//        }
        return getFormatSize(cacheSize);
    }


    /**
     * 清楚所有缓存
     *
     * @param context 上下文
     * @deprecated 不建议使用这个方法
     */
    @Deprecated
    public static void clearAllCache(Context context) {
        boolean b = deleteDirOrFile(context.getCacheDir());
//        Log.e("打印", "删除getCacheDir = " + b);
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            boolean b1 = deleteDirOrFile(context.getExternalCacheDir());
//            Log.e("打印", "删除getExternalCacheDir = " + b1);
        }
//        File file = new File(BitmapUtils.IMAGE_FILE_PATH);
//        if (file.isDirectory()){
//            boolean b1 = deleteDirOrFile(file);
//            Log.e("打印", "删除IMAGE_FILE_PATH = " + b1);
//        }
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////以上是被废弃的/////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * 删除文件
     *
     * @param url 文件路径
     * @return 是否删除成功, true是成功
     */
    public static boolean deleteFile(String url) {
        if (TextUtils.isEmpty(url)) {
            return true;
        }
        try {
            File file = new File(url);
            return deleteFile(file);
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * 删除文件
     *
     * @param dirOrFile 文件
     * @return 是否删除成功, true是成功
     */
    public static boolean deleteFile(File dirOrFile) {
        if (dirOrFile == null || !dirOrFile.exists()) {
            return true;
        }
        try {
            return deleteDirOrFile(dirOrFile);
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * 删除文件
     *
     * @param dirOrFile 文件
     * @return 是否删除成功, true是成功
     */
    private static boolean deleteDirOrFile(File dirOrFile) {
        if (dirOrFile != null) {
            if (dirOrFile.isDirectory()) {
                String[] children = dirOrFile.list();
                for (String aChildren : children) {
                    boolean success = deleteDirOrFile(new File(dirOrFile, aChildren));
                    if (!success) {
                        return false;
                    }
                }
            }
            return dirOrFile.delete();
        }
        return true;
    }

    // 获取文件
    //Context.getExternalFilesDir() --> SDCard/Android/data/你的应用的包名/files/ 目录，一般放一些长时间保存的数据
    //Context.getExternalCacheDir() --> SDCard/Android/data/你的应用包名/cache/目录，一般存放临时缓存数据
    public static long getFolderSize(File file) {
        long size = 0;
        try {
            if (file == null || !file.exists()) return size;

            File[] fileList = file.listFiles();
            for (File aFileList : fileList) {
                // 如果下面还有文件
                if (aFileList.isDirectory()) {
                    size = size + getFolderSize(aFileList);
                } else {
                    size = size + aFileList.length();
                }
            }
        } catch (Exception e) {
            Logger.e("获取文件异常", e);
        }
        return size;
    }

    /**
     * 格式化单位
     *
     * @param size 长度
     * @return 单位
     */
    public static String getFormatSize(float size) {
        double kiloByte = size / 1024;
        if (kiloByte < 1) {
            return "0Byte";
        }

        double megaByte = kiloByte / 1024;
        if (megaByte < 1) {
            BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
            return result1.setScale(2, BigDecimal.ROUND_HALF_UP)
                .toPlainString() + "KB";
        }

        double gigaByte = megaByte / 1024;
        if (gigaByte < 1) {
            BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
            return result2.setScale(2, BigDecimal.ROUND_HALF_UP)
                .toPlainString() + "MB";
        }

        double teraBytes = gigaByte / 1024;
        if (teraBytes < 1) {
            BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
            return result3.setScale(2, BigDecimal.ROUND_HALF_UP)
                .toPlainString() + "GB";
        }
        BigDecimal result4 = new BigDecimal(teraBytes);
        return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()
            + "TB";
    }


    public static final int VIDEO_WIDTH = 0, VIDEO_HEIGHT = 1, VIDEO_ROTATION = 2;

    /**
     * 不加载视频, 通过检索本地资源获取视频宽高, 注意, 只能获取本地视频!
     *
     * @param videoPath 本地视频路径
     * @return 宽 {@link #VIDEO_WIDTH} , 高 {@link #VIDEO_HEIGHT}, 旋转角 {@link #VIDEO_ROTATION}
     * @deprecated 文件provide 可能出错, 建议使用{@link #getVideoWidthAndHeight(Context, Uri)}
     */
    public static int[] getVideoWidthAndHeight(String videoPath) {
        MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
        mediaMetadataRetriever.setDataSource(videoPath);
        String s = "0";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            s = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
        }
        String videoW = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
        String videoH = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
        int[] wh = new int[3];
        if (s.equals("90") || s.equals("270")) {
            wh[VIDEO_HEIGHT] = Integer.valueOf(videoW);
            wh[VIDEO_WIDTH] = Integer.valueOf(videoH);
        } else if (s.equals("0") || s.equals("180") || s.equals("360")) {
            wh[VIDEO_WIDTH] = Integer.valueOf(videoW);
            wh[VIDEO_HEIGHT] = Integer.valueOf(videoH);
        }
        wh[VIDEO_ROTATION] = Integer.valueOf(s);
        return wh;
    }

    /**
     * 不加载视频, 通过检索本地资源获取视频宽高, 注意, 只能获取本地视频!
     *
     * @param videoUri 本地视频路径
     * @return 宽 {@link #VIDEO_WIDTH} , 高 {@link #VIDEO_HEIGHT}, 旋转角 {@link #VIDEO_ROTATION}
     */
    public static int[] getVideoWidthAndHeight(Context mContext, Uri videoUri) {
        MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
        mediaMetadataRetriever.setDataSource(mContext, videoUri);
        String s = "0";
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            s = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
        }
        String videoW = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
        String videoH = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
        int[] wh = new int[3];
        if (s.equals("90") || s.equals("270")) {
            wh[VIDEO_HEIGHT] = Integer.valueOf(videoW);
            wh[VIDEO_WIDTH] = Integer.valueOf(videoH);
        } else if (s.equals("0") || s.equals("180") || s.equals("360")) {
            wh[VIDEO_WIDTH] = Integer.valueOf(videoW);
            wh[VIDEO_HEIGHT] = Integer.valueOf(videoH);
        }
        wh[VIDEO_ROTATION] = Integer.valueOf(s);
        return wh;
    }


    ////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////创建缓存文件夹或文件///////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////


    /**
     * 必须要先确保读写权限的请求！
     *
     * @param displayName 文件名含后缀
     * @param dirName     文件夹名，开头"/"
     * @return 创建的SdCard 文件
     */
    public static File getNewFile(String displayName, @Nullable String dirName) {
        if (TextUtils.isEmpty(displayName)) {
            return null;
        }
        if (dirName == null || dirName.length() == 0 || !dirName.startsWith("/")) {
            dirName = "/" + dirName;
        }

        File outputDir = new File(Environment.getExternalStorageDirectory(), dirName);
        File newFile = new File(outputDir, displayName);
        if (outputDir.exists() || outputDir.mkdirs()) {
            try {
                if (!newFile.exists()) {
                    if (!newFile.createNewFile()) {
                        Logger.e("创建文件错误");
                        return null;
                    }
                }
                return newFile;
            } catch (Exception e) {
                Logger.e("创建文件异常", e);
            }
        }
        return null;
    }

    /**
     * 获取一个新的缓存文件, 即在缓存目录里面创建一个待写入的缓存文件
     *
     * @param mContext    上下文
     * @param displayName 文件名 ( 包含后缀的)
     * @param type        缓存文件夹类型, 可为空, 参考{@link #getCacheDirectory(Context, String)}
     * @return 待写入的新文件
     */
    public static File getNewInternalCacheFile(Context mContext, String displayName, @Nullable String type) {
        if (TextUtils.isEmpty(displayName)) {
            return null;
        }
        File outputDir = FileUtils.getInternalCacheDirectory(mContext, type);
        File newFile = new File(outputDir, displayName);
        if (outputDir.exists() || outputDir.mkdirs()) {
            try {
                if (!newFile.exists()) {
                    if (!newFile.createNewFile()) {
                        Logger.e("创建文件错误");
                        return null;
                    }
                }
                return newFile;
            } catch (Exception e) {
                Logger.e("创建文件异常", e);
            }
        }
        return null;
    }
    /**
     * 获取一个新的缓存文件, 即在缓存目录里面创建一个待写入的缓存文件
     *
     * @param mContext    上下文
     * @param displayName 文件名 ( 包含后缀的)
     * @param type        缓存文件夹类型, 可为空, 参考{@link #getCacheDirectory(Context, String)}
     * @return 待写入的新文件
     */
    public static File getNewCacheFile(Context mContext, String displayName, @Nullable String type) {
        if (TextUtils.isEmpty(displayName)) {
            return null;
        }
        File outputDir = FileUtils.getCacheDirectory(mContext, type);
        File newFile = new File(outputDir, displayName);
        if (outputDir.exists() || outputDir.mkdirs()) {
            try {
                if (!newFile.exists()) {
                    if (!newFile.createNewFile()) {
                        Logger.e("创建文件错误");
                        return null;
                    }
                }
                return newFile;
            } catch (Exception e) {
                Logger.e("创建文件异常", e);
            }
        }
        return null;
    }


    /**
     * 获取应用专属缓存目录, 推荐使用这个用来存储文件
     * android 4.4及以上系统不需要申请SD卡读写权限
     * 因此也不用考虑6.0系统动态申请SD卡读写权限问题，切随应用被卸载后自动清空 不会污染用户存储空间
     *
     * @param context 上下文
     * @param type    文件夹类型 可以为空，为空则返回API得到的一级目录
     *                如果为空则返回 /storage/emulated/0/Android/data/app_package_name/cache
     *                否则返回对应类型的文件夹如Environment.DIRECTORY_PICTURES
     *                对应的文件夹为 .../data/app_package_name/files/Pictures
     *                {@link Environment#DIRECTORY_MUSIC},
     *                {@link Environment#DIRECTORY_PODCASTS},
     *                {@link Environment#DIRECTORY_RINGTONES},
     *                {@link Environment#DIRECTORY_ALARMS},
     *                {@link Environment#DIRECTORY_NOTIFICATIONS},
     *                {@link Environment#DIRECTORY_PICTURES}, or
     *                {@link Environment#DIRECTORY_MOVIES}.or 自定义文件夹名称
     * @return 缓存文件夹 如果没有SD卡或SD卡有问题则返回内存缓存目录，否则优先返回SD卡缓存目录
     */
    public static File getCacheDirectory(Context context, @Nullable String type) {
        File appCacheDir = getExternalCacheDirectory(context, type);
        if (appCacheDir == null) {
            appCacheDir = getInternalCacheDirectory(context, type);
        }

        if (appCacheDir == null) {
            Logger.e("getCacheDirectory fail ,the reason is mobile phone unknown exception !");
        } else {
            if (!appCacheDir.exists() && !appCacheDir.mkdirs()) {
                Logger.e("getCacheDirectory fail ,the reason is make directory fail !");
            }
        }
        return appCacheDir;
    }

    /**
     * 获取SD卡缓存目录
     *
     * @param context 上下文
     * @param type    文件夹类型 如果为空则返回 /storage/emulated/0/Android/data/app_package_name/cache
     *                否则返回对应类型的文件夹如Environment.DIRECTORY_PICTURES 对应的文件夹为 .../data/app_package_name/files/Pictures
     *                {@link Environment#DIRECTORY_MUSIC},
     *                {@link Environment#DIRECTORY_PODCASTS},
     *                {@link Environment#DIRECTORY_RINGTONES},
     *                {@link Environment#DIRECTORY_ALARMS},
     *                {@link Environment#DIRECTORY_NOTIFICATIONS},
     *                {@link Environment#DIRECTORY_PICTURES}, or
     *                {@link Environment#DIRECTORY_MOVIES}.or 自定义文件夹名称
     * @return 缓存目录文件夹 或 null（无SD卡或SD卡挂载失败）
     */
    public static File getExternalCacheDirectory(Context context, @Nullable String type) {
        File appCacheDir = null;
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
            if (TextUtils.isEmpty(type)) {
                appCacheDir = context.getExternalCacheDir();
            } else {
                appCacheDir = context.getExternalFilesDir(type);
            }

            if (appCacheDir == null) {// 有些手机需要通过自定义目录
                appCacheDir = new File(Environment.getExternalStorageDirectory(),
                    "Android/data/" + context.getPackageName() + "/cache/" + type);
            }

            if (!appCacheDir.exists()) {
                Logger.e("getExternalDirectory fail ,the reason is sdCard unknown exception !");
            } else {
                if (!appCacheDir.exists() && !appCacheDir.mkdirs()) {
                    Logger.e("getExternalDirectory fail ,the reason is make directory fail !");
                }
            }
        } else {
            Logger.e("getExternalDirectory fail ,the reason is sdCard nonexistence or sdCard mount fail !");
        }
        return appCacheDir;
    }

    /**
     * 获取内存缓存目录
     *
     * @param type 子目录，可以为空，为空直接返回一级目录
     * @return 缓存目录文件夹 或 null（创建目录文件失败）
     * 注：该方法获取的目录是能供当前应用自己使用，外部应用没有读写权限，如 系统相机应用
     */
    public static File getInternalCacheDirectory(Context context, @Nullable String type) {
        File appCacheDir;
        if (TextUtils.isEmpty(type)) {
            appCacheDir = context.getCacheDir();// /data/data/app_package_name/cache
        } else {
            appCacheDir = new File(context.getFilesDir(), type);// /data/data/app_package_name/files/type
        }

        if (!appCacheDir.exists() && !appCacheDir.mkdirs()) {
            Logger.e("getInternalDirectory fail ,the reason is make directory fail !");
        }
        return appCacheDir;
    }


    ////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////获取文件类型//////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////


    /**
     * 获取文件类型
     *
     * @param file 文件
     * @return 类型字符串
     */
    public static String getMimeType(File file) {
        String mime = "text/plain";
        if (file == null || !file.exists() || file.isDirectory()) {
            return mime;
        }
        try {
            String fileName = file.getName();
            if (!TextUtils.isEmpty(fileName)) {
                int index = fileName.lastIndexOf(".");
                if (index != -1 && !fileName.endsWith(".")) {
                    String suffix = fileName.substring(index + 1).toLowerCase(Locale.US);
                    String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(suffix);
                    if (!TextUtils.isEmpty(type)) {
                        return type;
                    }
                }
            }
        } catch (Exception e) {
            Logger.e("获取文件类型异常", e);
        }
        MediaMetadataRetriever mmr = new MediaMetadataRetriever();
        try {
            mmr.setDataSource(file.getAbsolutePath());
            mime = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_MIMETYPE);
        } catch (IllegalStateException e) {
            Logger.e("获取文件类型异常", e);
        } catch (IllegalArgumentException e) {
            Logger.e("获取文件类型异常", e);
        } catch (RuntimeException e) {
            Logger.e("获取文件类型异常", e);
        } finally {
            mmr.release();
        }
        return mime;
    }


    ////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////读写文件，耗时的，最好放异步/////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////


    /**
     * 获取文本里面的内容
     *
     * @param filePath 文本文件路径
     * @return 字符串
     */
    public static String readStrFromTxT(String filePath) {
        return readStrFromTxT(new File(filePath));
    }

    /**
     * 获取文本里面的内容
     *
     * @param file 文本文件
     * @return 字符串
     */
    public static String readStrFromTxT(File file) {
        if (file != null && file.isFile() && file.exists()) {
            StringBuilder mBuilder = new StringBuilder();
            FileInputStream is = null;
            BufferedReader br = null;
            InputStreamReader isr = null;
            try {
                is = new FileInputStream(file);
                isr = new InputStreamReader(is);
                br = new BufferedReader(isr);
                String line;
                while ((line = br.readLine()) != null) {
                    mBuilder.append(line);
                }
            } catch (FileNotFoundException e) {
                Logger.e("文件载入异常", e);
            } catch (IOException e) {
                Logger.e("文件解析异常", e);
            } finally {
                try {
                    if (is != null) {
                        is.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (br != null) {
                        br.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (isr != null) {
                        isr.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return mBuilder.toString();
        }
        return null;
    }

    /**
     * 获取文本里面的内容
     *
     * @param fileInputStream assets 里面的文件资源
     * @return 字符串
     */
    public static String readStrFromAssetTxT(InputStream fileInputStream) {
        if (fileInputStream != null) {
            StringBuilder mBuilder = new StringBuilder();
            BufferedReader br = null;
            InputStreamReader isr = null;
            try {
                isr = new InputStreamReader(fileInputStream);
                br = new BufferedReader(isr);
                String line;
                while ((line = br.readLine()) != null) {
                    mBuilder.append(line);
                }
            } catch (FileNotFoundException e) {
                Logger.e("文件载入异常", e);
            } catch (IOException e) {
                Logger.e("文件解析异常", e);
            } finally {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (br != null) {
                        br.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    if (isr != null) {
                        isr.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return mBuilder.toString();
        }
        return null;
    }


    /**
     * 保存 图片二进制流到本地成为文件
     *
     * @param bytes 图片二进制数组
     * @return 文件
     */
    public static File saveByte2FileInLocal(byte[] bytes, String displayName, String dirName) {
        if (bytes == null || bytes.length <= 0) return null;
        File newFile = getNewFile(displayName, dirName);
        if (newFile == null || !newFile.exists() && !newFile.mkdirs()) {
            return null;
        }
        // 创建FileOutputStream对象
        FileOutputStream outputStream = null;
        // 创建BufferedOutputStream对象
        BufferedOutputStream bufferedOutputStream = null;
        try {
            // 获取FileOutputStream对象
            outputStream = new FileOutputStream(newFile);
            // 获取BufferedOutputStream对象
            bufferedOutputStream = new BufferedOutputStream(outputStream);
            // 往文件所在的缓冲输出流中写byte数据
            bufferedOutputStream.write(bytes);
            // 刷出缓冲输出流，该步很关键，要是不执行flush()方法，那么文件的内容是空的。
            bufferedOutputStream.flush();
            return newFile;
        } catch (Exception e) {
            // 打印异常信息
            Logger.e("存储异常", e);
        } finally {
            // 关闭创建的流对象
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    Logger.e("关流异常", e);
                }
            }
            if (bufferedOutputStream != null) {
                try {
                    bufferedOutputStream.flush();
                    bufferedOutputStream.close();
                } catch (Exception e) {
                    Logger.e("关流异常", e);
                }
            }
        }
        return null;
    }

    /**
     * 写文件到本地, 需要写入权限
     *
     * @param str       字符
     * @param fileName  文件名，包含后缀
     * @param outputDir 输出的文件夹路径
     */
    public static File saveString2FileInLocal(String str, String fileName, String outputDir) {
        File file = getNewFile(fileName, outputDir);//文件夹路径
        if (file == null) {
            return null;
        }
        FileOutputStream fos = null;
        // 创建FileOutputStream对象
        try {
            // 如果文件存在则删除, 然后在文件系统中根据路径创建一个新的空文件
            if (file.exists()) {
                if (file.delete() && !file.createNewFile()) {
                    return null;
                }
            }
            // 获取FileOutputStream对象
            fos = new FileOutputStream(file);
            fos.write(str.getBytes());
            return file;
        } catch (Exception e) {
            // 打印异常信息
            Logger.e("写入异常", e);
        } finally {
            // 关闭创建的流对象
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    Logger.e("流关闭异常", e);
                }
            }
        }
        return null;
    }


    ////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////// 复制文件，最好放异步 /////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * 复制文件
     *
     * @param context 上下文
     * @param srcUri  源路径
     * @param dstFile 目标路径
     */
    public static void copyFile(Context context, Uri srcUri, File dstFile) {
        try {
            InputStream inputStream = context.getContentResolver().openInputStream(srcUri);
            if (inputStream == null) return;
            OutputStream outputStream = new FileOutputStream(dstFile);
            copyStream(inputStream, outputStream);
            inputStream.close();
            outputStream.close();
        } catch (IOException e) {
            Logger.e("复制文件异常", e);
        }
    }

    /**
     * 将目标流写入到对应位置
     *
     * @param input  目标流
     * @param output 输出位置
     * @return 文件大小
     * @throws IOException 流异常
     */
    public static int copyStream(InputStream input, OutputStream output) throws IOException {
        final int BUFFER_SIZE = 1024 * 2;
        byte[] buffer = new byte[BUFFER_SIZE];
        BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);
        BufferedOutputStream out = new BufferedOutputStream(output, BUFFER_SIZE);
        int count = 0, n;
        while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
            out.write(buffer, 0, n);
            count += n;
        }
        out.flush();
        out.close();
        in.close();
        return count;
    }


    ////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////// 对 uri 和 文件 的互转 /////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * 转换file 变成 uri ( 在安卓 7.0 以后, 请求文件 URI 需要进行安全转换 )
     *
     * @param mContext  上下文
     * @param mFile     文件
     * @param authority FileProvider参数, 来自清单文件注册参数 authorities
     *                  <p>
     *                  <provider
     *                  android:name="android.support.v4.content.FileProvider"
     *                  android:authorities="cn.ydw.www.test.provider"
     *                  android:exported="false"
     *                  android:grantUriPermissions="true">
     *                  <meta-data
     *                  android:name="android.support.FILE_PROVIDER_PATHS"
     *                  android:resource="@xml/tool_file_paths" />
     *                  </provider>
     *                  </p>
     * @return uri
     * （文件 = file:///storage/emulated/0/Huawei/MagazineUnlock/magazine.jpg）
     * （转后的图片 = content://cn.ydw.www.test.provider/ydw_root_images/storage/emulated/0/Huawei/MagazineUnlock/magazine.jpg）
     * （注：该uri转文件使用substring方法）
     */
    public static Uri coverFile2Uri(Context mContext, File mFile, String authority) {
        Uri uri;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            uri = FileProvider.getUriForFile(mContext, authority, mFile);
        } else {
            uri = Uri.fromFile(mFile);
        }
        return uri;
    }

    /**
     * 将图片 file 变成 uri （兼容了高版本，需要{@link Manifest.permission#WRITE_EXTERNAL_STORAGE}权限）
     *
     * @param context   上下文
     * @param imageFile 图片文件
     * @return uri
     * （文件 = file:///storage/emulated/0/Huawei/MagazineUnlock/magazine.jpg）
     * （转后的图片 = content://media/external/images/media/36185）
     * （注：该uri转文件使用cursor方法） 暂未测试普通file是否可以装换
     */
    public static Uri coverImageFile2Uri(Context context, File imageFile) {
        String filePath = imageFile.getAbsolutePath();
        Cursor cursor = context.getContentResolver()
            .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                new String[]{MediaStore.Images.Media._ID},
                MediaStore.Images.Media.DATA + "=? ",
                new String[]{filePath}, null);
        if (cursor != null) {
            Uri mUri = null;
            if (cursor.moveToFirst()) {
                int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
                mUri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, String.valueOf(id));
            }
            cursor.close();
//            Logger.e("Cover file to uri is use 'cursor'");
            return mUri;
        } else {
            if (imageFile.exists()) {
                ContentValues values = new ContentValues();
                values.put(MediaStore.Images.Media.DATA, filePath);
//                Logger.e("Cover file to uri is use 'contentResolver'");
                return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            } else {
                return null;
            }
        }
    }

    /**
     * 转换file 变成 uri ( 在安卓 7.0 以后, 请求文件 URI 需要进行安全转换 ) , 这里使用取巧方式
     *
     * @param mFile 文件
     * @return uri
     * @deprecated 不推荐，可能有问题
     */
    /*@hint*/
    @Deprecated
    public static Uri coverFile2Uri(File mFile) {
        if (mFile != null && mFile.exists()) {
            return Uri.parse(("file://" + mFile.getAbsolutePath()));
        }
        return null;
    }

    /**
     * 使用取巧的方式将uri转换成文件地址
     *
     * @param uri 地址
     * @return 文件地址
     * @deprecated 不推荐，可能有问题
     */
    /*@hint*/
    @Deprecated
    private static String getFilePathFromUri(Uri uri) {
        if (uri != null) {
            String mPath = uri.getPath();
            if (mPath != null && mPath.length() > 0) {
                int mIndex = mPath.indexOf("/storage/");
                if (mIndex != -1) {
                    return mPath.substring(mIndex);
                }
            }
        }
        return null;
    }

    /**
     * Try to return the absolute file path from the given Uri
     *
     * @param context 上下文
     * @param uri     路径
     * @return the file path or null
     */
    public static String coverUri2FilePath(final Context context, final Uri uri) {
        if (null == uri) return null;
        final String scheme = uri.getScheme();
        String data = null;
        if (scheme == null || ContentResolver.SCHEME_FILE.equals(scheme)) {
            data = uri.getPath(); //调用get 方法
        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
            Cursor cursor = context.getContentResolver().query(uri, new String[]{
                MediaStore.Files.FileColumns.DATA}, null, null, null);
            if (null != cursor) {
                if (cursor.moveToFirst()) {
                    int index = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA);
                    if (index > -1) {
                        data = cursor.getString(index); //调用cursor 方法
                    }
                }
                cursor.close();
            }
            if (TextUtils.isEmpty(data)) {
                //noinspection deprecation
                data = getFilePathFromUri(uri); //调用substring 方法
                if (TextUtils.isEmpty(data)) {
                    data = getFilePathFromUri(context, uri); //调用copy 方法
                }
            }
        }
        return data;
    }

    /**
     * 将uri用复制的方法转变成file
     *
     * @param context 上下文
     * @param uri     地址
     * @return 文件地址
     */
    private static String getFilePathFromUri(Context context, Uri uri) {
        if (uri == null) return null;
        //copy file and send new file path
        String fileName = null;
        String path = uri.getPath();
        if (path != null) {
            int cut = path.lastIndexOf('/');
            if (cut != -1) {
                fileName = path.substring(cut + 1);
            }
        }
        if (!TextUtils.isEmpty(fileName)) {
            File copyFile = FileUtils.getNewCacheFile(context, fileName, Environment.DIRECTORY_DCIM);
            copyFile(context, uri, copyFile);
            if (copyFile != null) {
                return copyFile.getAbsolutePath();
            }
        }
        return null;
    }




    // =========
    // =通过URI获取本地图片的path
    // =兼容android 5.0
    // ==========
    public static String coverUri2Path(final Context context, final Uri uri) {
        final boolean isKitKat = Build.VERSION.SDK_INT >= 19;

        // DocumentProvider
        if (isKitKat && isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if ("com.android.externalstorage.documents".equals(uri.getAuthority())) {
                // Whether the Uri authority is ExternalStorageProvider.
                final String docId = getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                }

            }
            // DownloadsProvider
            else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
                // Whether the Uri authority is DownloadsProvider.
                final String id = getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
                    Long.valueOf(id));

                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
                // Whether the Uri authority is MediaProvider.
                final String docId = getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{split[1]};

                return getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {

            // Return the remote address
            if ("com.google.android.apps.photos.content".equals(uri.getAuthority()))
                // Whether the Uri authority is Google Photos.
                return uri.getLastPathSegment();

            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }

        return null;
    }

    private static final String PATH_DOCUMENT = "document";

    /**
     * Test if the given URI represents a {@link DocumentsContract.Document} backed by a
     * {@link DocumentsProvider}.
     */
    private static boolean isDocumentUri(Context context, Uri uri) {
        final List<String> paths = uri.getPathSegments();
        if (paths.size() < 2) {
            return false;
        }
        return PATH_DOCUMENT.equals(paths.get(0));
    }

    private static String getDocumentId(Uri documentUri) {
        final List<String> paths = documentUri.getPathSegments();
        if (paths.size() < 2) {
            throw new IllegalArgumentException("Not a document: " + documentUri);
        }
        if (!PATH_DOCUMENT.equals(paths.get(0))) {
            throw new IllegalArgumentException("Not a document: " + documentUri);
        }
        return paths.get(1);
    }

    /**
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context       The context.
     * @param uri           The Uri to query.
     * @param selection     (Optional) Filter used in the query.
     * @param selectionArgs (Optional) Selection arguments used in the query.
     *                      [url=home.php?mod=space&uid=7300]@return[/url] The value of
     *                      the _data column, which is typically a file path.
     */
    public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = {column};

        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }
}
